package org.yunai.swjg.server.module.scene.core;

import org.slf4j.Logger;
import org.yunai.swjg.server.core.annotation.SceneThread;
import org.yunai.swjg.server.core.constants.SceneConstants;
import org.yunai.swjg.server.core.service.Online;
import org.yunai.swjg.server.module.player.vo.Player;
import org.yunai.swjg.server.module.scene.core.msg.SysPlayerLeaveScene;
import org.yunai.swjg.server.rpc.message.S_C.S_C_ScenePlayerChangePosResp;
import org.yunai.swjg.server.rpc.message.S_C.S_C_SceneSelfChangePosResp;
import org.yunai.yfserver.common.LoggerFactory;
import org.yunai.yfserver.util.CollectionUtils;
import org.yunai.yfserver.util.ObjectUtils;

/**
 * 场景Service基类
 * User: yunai
 * Date: 13-5-14
 * Time: 下午3:39
 */
public abstract class AbstractSceneService<T extends AbstractScene> {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggerFactory.Logger.scene, AbstractSceneService.class);

    /**
     * [主线程]处理玩家离开场景<br />
     * 若离开场景成功，则给[场景消息队列]发消息来进行之后的逻辑
     * <p/>
     * //     * @param sceneService 离开场景的管理者sceneService
     *
     * @param online   在线信息
     * @param callback 离开场景后的回调
     */
//    @MainThread
    // TODO 改成SceneThread
    @SceneThread
    public void onPlayerLeaveScene(Online online, SceneCallable callback) {
        // 检查场景是否为空，若为空，则无法进行离开场景逻辑
        AbstractScene scene = online.getScene();
        if (scene == null) {
            LOGGER.error("[onPlayerLeaveScene] [online:{}] [scene:{} is not exist].", online.getPlayer().getId(),
                    online.getPlayer().getSceneId());
            return;
        }
        // 设置场景为空
//        online.setScene(null); TODO 移到场景线程去做，想下对线程回收的影响。
//        scene.removeOnline(online);
        // 设置玩家所在场景，并给场景发送离开的消息
        SysPlayerLeaveScene playerLeaveScene = new SysPlayerLeaveScene(this, online.getPlayer().getId(), scene.getSceneId(), scene.getLine(), callback);
        scene.putMessage(playerLeaveScene);
    }

    /**
     * [场景线程]处理玩家离开
     *
     * @param online  在线信息
     * @param sceneId 离开场景编号
     */
    @SceneThread
    public void handleLevelScene(Online online, Integer sceneId, Integer line) {
        AbstractScene scene = online.getScene();
        if (scene != null) {
            scene.onPlayerLevel(online);
        } else {
            LOGGER.error("[handleLevelScene] [online:{} leave scene failure] [scene:{} line:{} is not exist].", online.getPlayer().getId(), sceneId, line);
        }
    }

    /**
     * 复活<br />
     * 分成2种方式复活.<br />
     * 1. 复活在当前场景的某个坐标，已经实现。
     * 2. 复活在别的场景，暂未实现，无该需求。
     *
     * @param online  在线信息
     * @param sceneId 场景编号
     * @param sceneX  场景坐标X
     * @param sceneY  场景坐标Y
     */
    @SceneThread
    public void onRelive(Online online, Integer sceneId, Short sceneX, Short sceneY) {
        if (ObjectUtils.isNull(sceneId) || ObjectUtils.isNull(sceneX) || ObjectUtils.isNull(sceneY)) {
            return;
        }
        if (online.getScene().getSceneId().equals(sceneId)) { // 相同地图
            // 修改坐标
            Player player = online.getPlayer();
            player.moveSceneXY(sceneX, sceneY, (short) -1, (short) -1);
            // 广播坐标改变
            S_C_ScenePlayerChangePosResp scenePlayerChangePosResp = new S_C_ScenePlayerChangePosResp(player.getId(), sceneX, sceneY);
            online.getScene().broadcastMessage(scenePlayerChangePosResp, CollectionUtils.asSet(player.getId()));
            // 提示自己坐标改变
            S_C_SceneSelfChangePosResp sceneSelfChangePosResp = new S_C_SceneSelfChangePosResp(sceneX, sceneY);
            online.write(sceneSelfChangePosResp);
        } else {
            throw new Error("目前不支持复活到不同场景去。");
        }
    }

    /**
     * 复活在当前场景的通用坐标
     *
     * @param online 在线信息
     */
    public void onDefaultRelive(Online online) {
        onRelive(online, online.getScene().getSceneId(), SceneConstants.RELIVE_SCENE_X_DEFAULT, SceneConstants.RELIVE_SCENE_Y_DEFAULT);
    }

    /**
     * 获得场景
     *
     * @param sceneId 场景编号
     * @param line    场景线
     * @return 场景
     */
    protected abstract T getScene(Integer sceneId, Integer line);
}
